package com.boge.aop

import com.*
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.springframework.data.keyvalue.core.query.KeyValueQuery
import org.springframework.data.redis.repository.query.RedisOperationChain
import org.springframework.stereotype.Component

@Component
@Aspect
class RedisQueryAop {

    @Pointcut("execution(* org.springframework.data.keyvalue.core.KeyValueTemplate.find(..))")
    fun pointCut() {
    }

    @Around("pointCut()")
    fun handlerException(proceedingJoinPoint: ProceedingJoinPoint): Any? = runCatching {
        proceedingJoinPoint.args.ifOk {
            val key = this[0]
            if (key is KeyValueQuery<*>) {
                val criteria = key.criteria
                if (criteria is RedisOperationChain) {
                    if (criteria.sismember.size == 1
                        && criteria.orSismember.size == 0
                        && criteria.sismember.first().values().size == 1
                    ) { // 确定是批量查询
                        val path: String
                        val item: Any
                        criteria.sismember.first().run {
                            path = this.path
                            item = this.values().first()
                        }
                        val isBatch = when (item) {
                            is Iterable<*> -> true
                            is IntArray -> true
                            is LongArray -> true
                            is Array<*> -> true
                            else -> false
                        }
                        if (isBatch) {
                            criteria.sismember.clear()
                            when (item) {
                                is Iterable<*> -> {
                                    item.forEach { f ->
                                        criteria.orSismember(path, f!!)
                                    }
                                }
                                is IntArray -> item.forEach { f ->
                                    criteria.orSismember(path, f)
                                }

                                is LongArray -> item.forEach { f ->
                                    criteria.orSismember(path, f)
                                }

                                is Array<*> -> item.forEach { f ->
                                    criteria.orSismember(path, f!!)
                                }
                            }
                        }
                    }
                }
            }
        }
        proceedingJoinPoint.proceed()
    }.onFailure {
        log.error("redis query aop error. msg=${it.message}", it)
    }.getOrNull()


}